#!/bin/bash
# 进程僵死（无响应）自动处理脚本
FIX_CODE_ID="stuck"  # 对应知识图谱中"进程僵死（无响应）"故障ID


# 配置参数 - 根据实际情况修改
TARGET_PROCESS="apache2"  # 目标进程名
MONITOR_PORT=80           # 进程监听端口
HEARTBEAT_FILE="/var/run/${TARGET_PROCESS}/heartbeat"  # 进程心跳文件路径
LOG_FILE="/var/log/process_recovery.log"  # 操作日志文件
MAX_RESPAWN=5             # 最大重启次数（防止无限重启）
RESPAWN_INTERVAL=300      # 重启计数周期（秒）
CHECK_TIMEOUT=10          # 健康检查超时时间（秒）

# 日志函数
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# 检查进程是否存在
check_process_exist() {
    if pgrep -x "$TARGET_PROCESS" > /dev/null; then
        return 0  # 进程存在
    else
        return 1  # 进程不存在
    fi
}

# 检查进程是否响应（通过端口检测）
check_process_response() {
    # 尝试连接端口检查响应
    if nc -z -w $CHECK_TIMEOUT localhost $MONITOR_PORT; then
        return 0  # 端口响应正常
    else
        return 1  # 端口无响应
    fi
}

# 检查进程心跳（适用于有心跳机制的程序）
check_process_heartbeat() {
    if [ -f "$HEARTBEAT_FILE" ]; then
        # 检查心跳文件是否在最近30秒内更新过
        local last_modified=$(stat -c %Y "$HEARTBEAT_FILE")
        local current_time=$(date +%s)
        
        if [ $((current_time - last_modified)) -lt 30 ]; then
            return 0  # 心跳正常
        fi
    fi
    return 1  # 心跳异常或无心跳文件
}

# 统计指定时间内的重启次数
count_respawns() {
    local start_time=$(( $(date +%s) - RESPAWN_INTERVAL ))
    grep "成功重启进程" "$LOG_FILE" | while read -r line; do
        local log_time=$(echo "$line" | awk '{print $1 " " $2}')
        local log_timestamp=$(date -d "$log_time" +%s 2>/dev/null)
        if [ -n "$log_timestamp" ] && [ $log_timestamp -ge $start_time ]; then
            echo 1
        fi
    done | wc -l
}

# 终止僵死进程
kill_stuck_process() {
    local pids=$(pgrep -x "$TARGET_PROCESS")
    if [ -n "$pids" ]; then
        log "尝试终止僵死进程: $pids"
        
        # 先尝试正常终止
        kill $pids > /dev/null 2>&1
        sleep 5
        
        # 检查是否还有残留进程
        local remaining_pids=$(pgrep -x "$TARGET_PROCESS")
        if [ -n "$remaining_pids" ]; then
            log "正常终止失败，尝试强制终止"
            kill -9 $remaining_pids > /dev/null 2>&1
            sleep 2
        fi
        
        # 确认是否终止成功
        if pgrep -x "$TARGET_PROCESS" > /dev/null; then
            log "终止进程失败"
            return 1
        else
            log "成功终止所有进程实例"
            return 0
        fi
    else
        log "没有找到需要终止的进程"
        return 0
    fi
}

# 启动进程
start_process() {
    if systemctl is-enabled "$TARGET_PROCESS" > /dev/null 2>&1; then
        log "通过systemctl启动进程"
        systemctl start "$TARGET_PROCESS"
    else
        log "通过启动脚本启动进程"
        /etc/init.d/"$TARGET_PROCESS" start > /dev/null 2>&1
    fi
    
    sleep 5
    
    if check_process_exist && check_process_response; then
        log "成功重启进程 $TARGET_PROCESS"
        return 0
    else
        log "重启进程失败"
        return 1
    fi
}

# 主逻辑
main() {
    log "开始进程健康检查: $TARGET_PROCESS"
    
    # 检查重启次数是否超过限制
    local respawn_count=$(count_respawns)
    if [ $respawn_count -ge $MAX_RESPAWN ]; then
        log "达到最大重启次数 ($MAX_RESPAWN)，停止自动处理，需要人工干预"
        exit 1
    fi
    
    # 检查进程是否存在
    if ! check_process_exist; then
        log "进程不存在，尝试启动"
        start_process
        exit $?
    fi
    
    # 检查进程是否响应
    if ! check_process_response; then
        log "进程无响应（端口检测失败）"
        # 双重确认：检查心跳
        if ! check_process_heartbeat; then
            log "进程心跳异常，确认进程僵死"
            
            # 终止并重启进程
            if kill_stuck_process; then
                start_process
                exit $?
            else
                log "无法终止僵死进程，需要人工干预"
                exit 1
            fi
        fi
    fi
    
    log "进程状态正常"
    exit 0
}

# 执行主逻辑
main
    